package mse.tx.arch.pipe.systema;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Properties;

import mse.tx.arch.pipe.framework.FilterFramework;
import mse.tx.arch.pipe.framework.IConfigurable;

public class FileSinkFilter extends FilterFramework implements IConfigurable {

	// default value of file name	
	private String fileName = "OutputA.dat";
	
	// object is used to print a file
	private PrintWriter output = null;

	/**
	 * Constructor method which initializes normal input port
	 */
	
	public FileSinkFilter() {
		addInputPortByName("input");
	}
	
	/**
	 * Constructor method which initializes normal input port
	 * 
	 * @param name of file that this filter writes
	 */
	
	public FileSinkFilter(String fileName) {
		addInputPortByName("input");
		this.fileName = fileName;
	}

	public void run() {
		System.out.print("\n" + this.getName() + "::Sink Reading \n");

		Calendar timeStamp = Calendar.getInstance();
		SimpleDateFormat timeStampFormat = new SimpleDateFormat(
				"yyyy:DD:HH:mm:ss");

		long timestamp = 0;
		boolean isTimeRead = false;
		double altitude = 0;
		boolean isAltitudeRead = false;
		double temperature = 0;
		boolean isTemperatureRead = false;
		int id = 0;
		long measurement = 0;

		try {
			output = new PrintWriter(fileName);
			output.printf("Time: \t Temperature (C): \t Altitude (m):\n");

			while (true) {
				// write to file
				if (isTimeRead && isAltitudeRead && isTemperatureRead) {
					// write Time
					timeStamp.setTimeInMillis(timestamp);
					System.out.printf("%s\t",
							timeStampFormat.format(timeStamp.getTime()));
					output.printf("%s\t",
							timeStampFormat.format(timeStamp.getTime()));
					isTimeRead = false;

					// write Temperature
					//String temp = new String("9.5f");
					System.out.printf("%9.5f\t", temperature);
					output.printf("%9.5f\t", temperature);
					isTemperatureRead = false;

					// write Altitude
					System.out.printf("%11.5f\t", altitude);
					output.printf("%11.5f\t", altitude);
					isAltitudeRead = false;

					System.out.printf("\n");
					output.printf("\n");
				}

				// read temperature, altitude and pressure
				while (!(isTimeRead && isAltitudeRead && isTemperatureRead)) {
					id = readID();
					measurement = readMeasurement();

					switch (id) {
					case 0:
						timestamp = measurement;
						isTimeRead = true;
						break;
					case 1:
						Double.longBitsToDouble(measurement);
						break;
					case 2:
						altitude = Double.longBitsToDouble(measurement);
						isAltitudeRead = true;
						break;
					case 4:
						temperature = Double.longBitsToDouble(measurement);
						isTemperatureRead = true;
						break;
					case 5:
						Double.longBitsToDouble(measurement);
						break;
					case 7:
						Double.longBitsToDouble(measurement);
					default:
						break;
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (EndOfStreamException e) {
			// e.printStackTrace();
		} finally {
			output.close();
			closePorts();
		}
	}

	/**
	 *  
	 *  Private method which reads stream of measurement's ID and combine them as a variable
	 *  
	 *   @return a variable that contains 8 bytes of measurement's value
	 * */
	
	private int readID() throws IOException, EndOfStreamException {
		int IdLength = 4; // This is the length of IDs in the byte stream

		int id = 0;

		byte databyte;

		for (int i = 0; i < IdLength; i++) {
			databyte = readFilterInputPort("input");

			id = id | (databyte & 0xFF);

			if (i != IdLength - 1) {
				id = id << 8;
			}
		}
		return id;
	}

	/**
	 *  
	 *  Private method which reads stream of measurement value and combine them as a variable
	 *  
	 *   @return a variable that contains 8 bytes of measurement's value
	 * */
	
	private long readMeasurement() throws IOException, EndOfStreamException {
		int MeasurementLength = 8;

		long measurement = 0;

		byte databyte;

		for (int i = 0; i < MeasurementLength; i++) {
			databyte = readFilterInputPort("input");
			measurement = measurement | (databyte & 0xFF);
			if (i != MeasurementLength - 1) {
				measurement = measurement << 8;
			}
		}

		return measurement;
	}

	/**
	 * This method allows that filename can be set via property file
	 */
	@Override
	public void setConfiguration(Properties props) {
		if (props != null) {
			setFilename(props.getProperty("filename"));
		}
	}

	/**
	 * This method allow developers change file name
	 * 
	 * @param name of file that this filter read
	 */
	public void setFilename(String filename) {
		if (filename != null)
			this.fileName = filename;
	}

} // FilterTemplate